package com.biggabrotha {
	import flash.events.Event;
	import flash.events.NetStatusEvent;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.utils.getQualifiedClassName;
	import flash.utils.setInterval;

	import mx.controls.Alert;
	import mx.events.CloseEvent;
	import mx.managers.PopUpManager;
	import mx.managers.PopUpManagerChildList;


	public class MinistryOfConfiguration {

		private static var keyToTheStorage:String="MinistryOfConfiguration"; //or "THE_STORAGE"
		private static var pathToTheStorage:String="/"
		private static var theStorage:SharedObject

		private static var mih:MinistryOfHistory=new MinistryOfHistory()

		public function MinistryOfConfiguration() {
			super();
//							registerClassAlias(this.className, BiggaBrotha)
		}

		public static function save(dude:IConfigurable) {
			startCconfigure(dude, true)
		}

		public static function load(dude:IConfigurable) {
			startCconfigure(dude, false)
		}


		private static var dude:IConfigurable
		private static var doSave:Boolean
		private static var proToCos:Array
		private static var mocgui:MinistryOfConfigurationDialog

		/**
		 * Synchronizes the configurable properties between host and storage.
		 * If do Save is true, the property values from the given host are saved to the internal storage.
		 * Otherwise (yeah, false) the given host loads the values from the internal storage
		 * @param dude The host object which needs acute configuration
		 * @param doSave to save or not to save (which means to load)
		 * @return nothing, void, nada, niente, check for yourself!
		 *
		 */
		private static function startCconfigure(dude:IConfigurable, doSave:Boolean=false) {
			MinistryOfConfiguration.dude=dude
			MinistryOfConfiguration.doSave=doSave
			proToCos=dude.propertiesToConfigure
			if (proToCos == null) {
				trace("Nothing to configure so all work done, goodbye and thanks for the fish")
				return
			}

			try {
				theStorage=SharedObject.getLocal(keyToTheStorage, pathToTheStorage)
			} catch (error:Error) {
				mocgui=new MinistryOfConfigurationDialog()
				mocgui.addEventListener(CloseEvent.CLOSE, closeGUI)
				PopUpManager.addPopUp(mocgui, null, true, PopUpManagerChildList.APPLICATION)
				setInterval(tryAccessToSharedObject, 500)
			}
			if (theStorage == null) {
				//dont panic, an interval is set. we can do nothing about it now.
			} else
				doAfterStorageAcquired()

// only for loading
//			if (!theStorage.hasOwnProperty(dude_className)) {
//				return
//			}
		}

		/**
		 *
		 * @param showGUIonError if true, shows a popup and the flash security dialog for local storage if an error is thrown
		 * @return true, if access was possible, false otherwise
		 *
		 */
		static function tryAccessToSharedObject(showGUIonError:Boolean=false) {
			try {
				theStorage=SharedObject.getLocal(keyToTheStorage, pathToTheStorage)
				//if we get here, that means a lot
				closeGUI()
			} catch (error:Error) {
				//no luck yet
			}
		}

		static function closeGUI(e:Event=null) {
			PopUpManager.removePopUp(mocgui)
			if (theStorage == null)
				Alert.show("unsaved")
			else
				doAfterStorageAcquired()
		}

		static function doAfterStorageAcquired() {
			var dude_className:String=getQualifiedClassName(dude)
			trace("doSave: " + doSave)
			trace("dude: " + dude_className)
			var dudeStorage=theStorage.data[dude_className]
			if (dudeStorage == undefined) {
				if (doSave) {
					dudeStorage={}
					theStorage.data[dude_className]=dudeStorage
				} else {
					trace("no configuration found for class \"" + dude_className + "\"")
					return
				}
			}
			trace("property to Configure | type | host value | storage value")
			for (var i=0; i < proToCos.length; i++) {
				var proToCo:String=proToCos[i] as String
				if (proToCo == null) {
					trace("only Strings supported(, yet?)")
				}
				if (Object(dude).hasOwnProperty(proToCo)) {
					if (doSave)
						dudeStorage[proToCo]=dude[proToCo]
					else
						dude[proToCo]=dudeStorage[proToCo]
					var o_className=getQualifiedClassName(dude[proToCo])
					trace(proToCo + "|" + o_className + "|" + dude[proToCo] + "|" + dudeStorage[proToCo])
				} else {
					Alert.show("property \"" + proToCo + "\" specified in propertiesToConfigure not found in host")
				}
			}
//			theStorage.data[dude_className]=this;
			try {
				theStorage.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus)
				var result:String=theStorage.flush()
				if (result == SharedObjectFlushStatus.FLUSHED) {
					trace("all went well")
				} else if (result == SharedObjectFlushStatus.PENDING) {
					trace("lets wait and see")
				}
			} catch (e) {
				trace(e)
			}
		}

		static function onFlushStatus(e:NetStatusEvent) {
			trace(e)
			switch (e.info.code) {
				case "SharedObject.Flush.Success":
					trace("saved");
					break;
				case "SharedObject.Flush.Failed":
					trace("Big Brother is angry!", "unsaved")
					break;
			}
			theStorage.removeEventListener(NetStatusEvent.NET_STATUS, onFlushStatus)
		}
	}
}